package chen.yi.component.data.desensitization.interceptor;

import chen.yi.component.data.desensitization.annotation.SensitiveData;
import chen.yi.component.data.desensitization.annotation.SensitiveField;
import chen.yi.component.data.desensitization.decryption.DataDecryption;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;

/**
 * 加密拦截器
 * @author huat
 **/
@Component
@Intercepts({
        @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class),
})
public class EncryptInterceptor implements Interceptor {
    private final DataDecryption decryption;

    @Autowired
    public EncryptInterceptor(DataDecryption decryption) {
        this.decryption = decryption;
    }
    public Object intercept(Invocation invocation) throws Throwable {
        //@Signature 指定了 type= parameterHandler 后，这里的 invocation.getTarget() 便是parameterHandler
        //若指定ResultSetHandler ，这里则能强转为ResultSetHandler
        ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
        // 获取参数对像，即 mapper 中 paramsType 的实例
       // Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
//        parameterField.setAccessible(true);
        //取出实例,当parameterObject 是单独一个对象时
//        Object parameterObject = parameterField.get(parameterHandler);
        Object parameterObject = parameterHandler.getParameterObject();
        if (parameterObject != null) {
            Class<?> parameterObjectClass =null;
            //判断入参是否为map类型
            if(parameterObject instanceof MapperMethod.ParamMap ){
                Map paramMap = (Map) parameterObject;
                //判断key是否有et字符串
                if(paramMap.containsKey("et")){
                    parameterObject=paramMap.get("et");
                }

            }
            parameterObjectClass=parameterObject.getClass();
            //校验该实例的类是否被@SensitiveData所注解
            SensitiveData sensitiveData = AnnotationUtils.findAnnotation(parameterObjectClass, SensitiveData.class);
            if (Objects.nonNull(sensitiveData)) {
                //取出当前当前类所有字段，传入加密方法
                Field[] declaredFields = parameterObjectClass.getDeclaredFields();
                encrypt(declaredFields, parameterObject);
            }
        }
        return invocation.proceed();
    }

    /**
     * 解密
     * @param declaredFields
     * @param paramsObject
     */
    private void encrypt(Field[] declaredFields, Object paramsObject) throws IllegalAccessException {
        for (Field field : declaredFields) {
            //取出所有被EncryptDecryptField注解的字段
            SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
            //判断是否为空
            if (!Objects.isNull(sensitiveField)) {
                //反射设置允许获取私有属性
                field.setAccessible(true);
                //获取对象属性
                Object object = field.get(paramsObject);
                field.set(paramsObject,  decryption.encrypt(object));
            }
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
